package com.aliyun.messagemgt.sendplugin;

import com.aliyun.messagemgt.common.enums.PushResultEnum;
import com.aliyun.messagemgt.common.dto.send.MsgMiddleResult;
import com.aliyun.messagemgt.common.dto.send.MsgRecordVO;
import com.aliyun.messagemgt.common.dto.send.PushChannelInfo;
import com.aliyun.messagemgt.common.dto.send.Receiver;
import com.aliyun.messagemgt.common.enums.ChannelTypeEnum;
import com.aliyun.messagemgt.common.exception.BaseException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @ClassName: SendStrategyContext
 * @Description:
 * @Author: wugongzi
 * @Date: 2021/8/30 10:52
 * @Version: 1.0
 */
@Service
@Slf4j
public class SendStrategyContext {

    private static final Set<Integer> RESEND_ERRORCODE = new HashSet<>();

    static {
        // 确认重发及扩展
        // 预先写好可以重发对应的错误码
        RESEND_ERRORCODE.add(PushResultEnum.PUSH_TOKEN_INVALID.getErrorCode());
        RESEND_ERRORCODE.add(PushResultEnum.PUSH_DINGTALK_USER_NOTEXIT.getErrorCode());
        RESEND_ERRORCODE.add(PushResultEnum.PUSH_ROBOT_ERROR_CODE.getErrorCode());
        RESEND_ERRORCODE.add(PushResultEnum.WEIXIN_PUSH_ERROR.getErrorCode());
    }

    public void sendMessage(List<MsgRecordVO> msgRecordVos) {
        for (MsgRecordVO msgRecordVO : msgRecordVos) {
            // 存放最终的发送结果
            List<MsgMiddleResult> msgMiddleResultList = new ArrayList<>();
            List<MsgMiddleResult> results = msgRecordVO.getResults();
            List<PushChannelInfo> pushChannelInfoList = msgRecordVO.getPushChannelInfoList();
            if (CollectionUtils.isEmpty(pushChannelInfoList)) {
                // 生成具体的接收者维度的状态信息
                MsgMiddleResult msgMiddleResult = new MsgMiddleResult()
                        .setReceivers(msgRecordVO.getReceivers())
                        .setPushResultCode(PushResultEnum.CHANNELINFO_EXIST_ERORR.getErrorCode())
                        .setPushResultDescription(PushResultEnum.CHANNELINFO_EXIST_ERORR.getDescription());
                results.add(msgMiddleResult);
                msgMiddleResultList.addAll(results);
                msgRecordVO.setReceivers(new ArrayList<>());
                continue;
            }
            for (PushChannelInfo pushChannelInfo : pushChannelInfoList) {
                // 清空每个渠道的结果,统一由msgMiddleResultList收集结果，最后设置
                msgRecordVO.setResults(new ArrayList<>());
                Integer channelType = pushChannelInfo.getChannelType();
                Long pushChannelId = pushChannelInfo.getPushChannelId();
                String channelCode = pushChannelInfo.getChannelCode();
                List<Receiver> receivers = msgRecordVO.getReceivers();
                SendStrategy sendStrategy = SendStrategyFactory.getByType(channelType);
                if (sendStrategy == null) {
                    MsgMiddleResult msgMiddleResult = new MsgMiddleResult()
                            .setPushChannelId(pushChannelId)
                            .setPushChannelCode(channelCode)
                            .setPushChannelType(channelType)
                            .setPushChannelName(pushChannelInfo.getDescription())
                            .setReceivers(receivers)
                            .setPushResultCode(PushResultEnum.CHANNEL_HANDLER_ERORR.getErrorCode())
                            .setPushResultDescription(PushResultEnum.CHANNEL_HANDLER_ERORR.getDescription());
                    results.add(msgMiddleResult);
                    msgMiddleResultList.addAll(results);
                    msgRecordVO.setReceivers(new ArrayList<>());
                    continue;
                }
                log.info("{}发送消息", ChannelTypeEnum.getName(channelType));
                int failureResendTimes = msgRecordVO.getFailureResendTimes();
                RetryTemplate retryTemplate = RetryTemplate.builder()
                        // 设置重试次数
                        .maxAttempts(failureResendTimes)
                        // 设置重试间隔时间
                        .fixedBackoff((long) msgRecordVO.getFailureResendInterval() * 60 * 1000).build();
                List<Receiver> resendReceiver = new ArrayList<>();
                retryTemplate.execute(
                        context -> {
                            int retryCount = context.getRetryCount();
                            try {
                                // 设置需要失败重发的用户
                                if (!resendReceiver.isEmpty() && failureResendTimes > 1) {
                                    msgRecordVO.setReceivers(resendReceiver);
                                    // 清空上次的结果
                                    msgRecordVO.setResults(new ArrayList<>());
                                }
                                sendStrategy.sendMessage(pushChannelInfo, msgRecordVO);
                                List<MsgMiddleResult> results1 = msgRecordVO.getResults();
                                if (failureResendTimes == 1) {
                                    // 不重发的处理逻辑
                                    for (MsgMiddleResult result : results1) {
                                        // 处理渠道信息
                                        Long pushChannelId1 = result.getPushChannelId();
                                        if (Objects.isNull(pushChannelId1)) {
                                            result.setPushChannelId(pushChannelId)
                                                    .setPushChannelCode(channelCode)
                                                    .setPushChannelType(channelType)
                                                    .setPushChannelName(pushChannelInfo.getDescription());
                                            msgMiddleResultList.add(result);
                                        }
                                    }
                                } else {
                                    // 配置业务逻辑返回错误重发(对于部分成功部分失败的只重发发送失败的用户)
                                    for (MsgMiddleResult result : results1) {
                                        Long pushChannelId1 = result.getPushChannelId();
                                        if (Objects.isNull(pushChannelId1)) {
                                            result.setPushChannelId(pushChannelId)
                                                    .setPushChannelCode(channelCode)
                                                    .setPushChannelType(channelType)
                                                    .setPushChannelName(pushChannelInfo.getDescription());
                                        }
                                        // 失败重试逻辑
                                        if (RESEND_ERRORCODE.contains(result.getPushResultCode())) {
                                            // 把发送不成功的用户设置重发
                                            if (!PushResultEnum.PUSH_SUCCESS.getErrorCode().equals(result.getPushResultCode())) {
                                                List<Receiver> pushFailureReceivers = result.getReceivers();
                                                resendReceiver.clear();
                                                resendReceiver.addAll(pushFailureReceivers);
                                            }
                                        } else {
                                            // 成功的不需要重试
                                            msgMiddleResultList.add(result);
                                        }
                                    }
                                    if (!resendReceiver.isEmpty() && retryCount < (failureResendTimes - 1)) {
                                        throw new BaseException(PushResultEnum.PUSH_ERROR.getErrorCode().toString(), PushResultEnum.PUSH_ERROR.getDescription());
                                    }
                                }
                            } catch (Exception e) {
                                String message = e.getMessage();
                                log.warn("消息推送异常，retryCount:{},exception:{}", retryCount, message);
                                throw new RuntimeException(e);
                            }
                            return true;
                        }, context -> {
                            // 最后一次重试失败后(最后一次重试有异常抛出)执行逻辑
                            Throwable lastThrowable = context.getLastThrowable();
                            String message = lastThrowable.getMessage();
                            MsgMiddleResult msgMiddleResult = new MsgMiddleResult().setPushResultCode(PushResultEnum.PUSH_ERROR.getErrorCode())
                                    .setPushResultDescription(message).setReceivers(receivers);
                            msgMiddleResultList.add(msgMiddleResult);
                            return true;
                        }
                );
                // 每个渠道重新设置所有接收人
                msgRecordVO.setReceivers(receivers);
            }
            msgRecordVO.setResults(msgMiddleResultList);
        }
    }
}
